home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Meeting Pearls 4
/
Meeting Pearls Vol. IV (1996)(GTI - Schatztruhe)[!].iso
/
Pearls
/
dev
/
Language
/
CLisp
/
fd
/
read-fd.lsp
< prev
next >
Wrap
Lisp/Scheme
|
1996-08-12
|
6KB
|
152 lines
(in-package "AFFI")
(export 'make-partial-affi-file)
(defun read-fd-directive (stream macro-char)
(declare (ignore macro-char)
(special *fd-readtable*))
(unless (eq *readtable* *fd-readtable*)
(error "Not the FD-readtable: ~S" *readtable*))
(let ((*package* (find-package "KEYWORD"))
(case (readtable-case *readtable*)))
(unwind-protect
(progn
(setf (readtable-case *readtable*) :upcase)
(read stream t nil t))
(setf (readtable-case *readtable*) case))))
;;Problem: AmigaGuide uses * in OpenAmigaGuideA()
;; Replace it with attrs, see AutoDocs, which gives
;; APTR OpenAmigaGuideA( struct NewAmigaGuide *nag, struct TagItem *attrs )(a0/a1);
(defun make-fd-readtable (&optional (readtable-case :upcase))
(let ((readtable (copy-readtable nil)))
;; , and / separate registers
(set-syntax-from-char #\, #\ readtable)
(set-syntax-from-char #\/ #\ readtable)
;; * serves as a comment
(set-syntax-from-char #\* #\; readtable)
;; ## introduces specials
(set-macro-character #\# #'read-fd-directive t readtable)
;; we choose to preserve case for all function names
(setf (readtable-case readtable) readtable-case)
readtable))
;; TODO maybe better read strings by preserving case, because output will look nicer?
(defvar *fd-readtable* (make-fd-readtable)) ;or :preserve
(defun read-from-fd (stream &optional (eof-error-p t))
(let* ((unique "EoF")
(read
;; switch readtables very temporarily only
(let ((*readtable* *fd-readtable*))
(read stream nil unique))))
(if (eq read unique)
(if eof-error-p
(error "FD file ~S ended" stream)
:end)
read)))
;; funinfo ist {(function . (offset . mask))}*
(defun read-fd-functions (stream skip offset funinfo)
(let ((tag (read-from-fd stream nil)))
(etypecase tag
;;(null (return-from read-fd-functions funinfo))
(keyword
(ecase tag
(:base (error "##base only allowed once: ~S"))
(:bias (setq offset (- (read-from-fd stream))))
(:public (setq skip nil))
(:private (setq skip t))
(:end (return-from read-fd-functions funinfo)))
(read-fd-functions stream skip offset funinfo))
(symbol ;tag is function name
(let ((vars (read-from-fd stream))
(regs (read-from-fd stream)))
(unless (listp vars)
(error "No FFI variable names read from ~S: ~S" stream vars))
(unless (listp regs)
(error "No FFI register specification read from ~S: ~S" stream regs))
(read-fd-functions
stream skip (- offset 6)
(if skip funinfo
;;TODO hashtable instead of alist
(cons (list* tag offset (calc-register-mask
regs #'(lambda (reg sym) (string-equal reg (symbol-name sym)))))
funinfo))))))))
;;Problem: cia_lib.fd contains no library base
;; libinfo ist (basename . {(function offset . mask)}*)
(defun parse-fd (name)
(with-open-file (file name :direction :input)
(let ((*package* '#.*package*))
(unless (eq (read-from-fd file) :base)
(error "FD file does not start with ##base: ~S" file))
(let ((library (read-from-fd file)))
(unless (symbolp library)
(error "Not a library base name: ~S in ~S" library file))
(cons (if (char= (schar (symbol-name library) 0) #\_) ;strip leading underscore
(intern (subseq (symbol-name library) 1))
library)
(read-fd-functions file nil -30 ()))))))
;; Problem: current AFFI.D doesn't handle more than 8 args (uint32)
;; It's now 16 args (uint64)
(defun show-large-masks (libinfos)
(dolist (libinfo libinfos)
;;TODO hashtable instead of alist
(dolist (funinfo (rest libinfo))
(unless (typep (cddr funinfo) '(unsigned-byte 32))
(format t "~&;;Maybe too big mask for ~A in ~A~%" (car funinfo) (car libinfo))))))
;;Bignum mask for AddAppIconA in _WorkbenchBase
;;Bignum mask for CreateBehindHookLayer in _LayersBase
;;Bignum mask for CreateUpfrontHookLayer in _LayersBase
;;Bignum mask for CreateBehindLayer in _LayersBase
;;Bignum mask for CreateUpfrontLayer in _LayersBase
;;Bignum mask for ScrollWindowRaster in _IntuitionBase
;;Bignum mask for NewModifyProp in _IntuitionBase
;;Bignum mask for AutoRequest in _IntuitionBase
;;Bignum mask for ModifyProp in _IntuitionBase
;;Bignum mask for WriteChunkyPixels in _GfxBase
;;Bignum mask for ScrollRasterBF in _GfxBase
;;Bignum mask for WritePixelArray8 in _GfxBase
;;Bignum mask for ReadPixelArray8 in _GfxBase
;;Bignum mask for TextFit in _GfxBase
;;Bignum mask for BltMaskBitMapRastPort in _GfxBase
;;Bignum mask for BltBitMapRastPort in _GfxBase
;;Bignum mask for ClipBlit in _GfxBase
;;Bignum mask for ScrollRaster in _GfxBase
;;Bignum mask for BltPattern in _GfxBase
;;Bignum mask for BltTemplate in _GfxBase
;;Bignum mask for BltBitMap in _GfxBase
;;Bignum mask for DoPkt in _DOSBase
(defun make-partial-affi-file (name) ; name like "graphics.library"
;; writes file to current directory, reads from FD:<base>_lib.fd
(let ((fdlibinfo (parse-fd (format () "FD:~A_lib.fd" (pathname-name name))))
(*package* '#.*package*))
(with-open-file (stream
(namestring (make-pathname :type "affi" :defaults name))
:direction :output
:if-exists :error) ;at least for now
(princ "(in-package \"AFFI\")" stream)(terpri stream)
(format stream "(declare-library-base :~A ~S)~%" (car fdlibinfo) name)
(format stream "(format *error-output* \"~~&;;; Warning: Please adapt the prototypes for ~~S manually!~~%\" ~S)~%~%" name)
(dolist (ffinfo (nreverse (rest fdlibinfo)))
;; the current implementation of AFFI.D is limited:
(unless (typep (cddr ffinfo) '(unsigned-byte 32))
(princ ";; This mask may be too large for AFFI:" stream)
(terpri stream))
(format stream ";(defflibfun '~S '~S ~D #x~X '*"
(car ffinfo) ;Function
(car fdlibinfo) ;Library
(cadr ffinfo) ;Offset
(cddr ffinfo)) ;Mask
;; Here we abuse the knowledge that AFFI.D:reg_coding is 4:
(dotimes (i (ceiling (integer-length (cddr ffinfo)) 4))
(princ " '*" stream))
(princ ")" stream)(terpri stream))
(format stream "~%(provide ~S)~%" name)
(pathname stream))))